package com.reebake.ideal.security.web;

import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.StrUtil;
import com.reebake.ideal.security.service.SecurityMetadataSourceService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.Setter;
import org.springframework.http.HttpMethod;
import org.springframework.security.authorization.AuthenticatedAuthorizationManager;
import org.springframework.security.authorization.AuthoritiesAuthorizationManager;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;

public class SmartAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {

    @Setter
    private SecurityMetadataSourceService securityMetadataSourceService;

    private AuthoritiesAuthorizationManager authoritiesAuthorizationManager = new AuthoritiesAuthorizationManager();
    private AuthenticatedAuthorizationManager<Object> authenticatedAuthorizationManager = new AuthenticatedAuthorizationManager<>();
    private final TimedCache<String, Set<String>> securityMetaSource = CacheUtil.newTimedCache(0);
    private final TimedCache<String, Boolean> securityMetaSourceLoadedFlag = CacheUtil.newTimedCache(300 * 1000);
    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext requestAuthorizationContext) {
        HttpServletRequest request = requestAuthorizationContext.getRequest();
        if (securityMetaSourceLoadedFlag.isEmpty()) {
            Map<String, Set<String>> allAuthorities = securityMetadataSourceService.load();
            for (Map.Entry<String, Set<String>> entry : allAuthorities.entrySet()) {
                securityMetaSource.put(entry.getKey(), entry.getValue());
            }
            securityMetaSourceLoadedFlag.put(StrPool.AT, true);
        }
        if(!securityMetaSourceLoadedFlag.isEmpty() && !securityMetaSource.isEmpty()) {
            String requestURI = request.getRequestURI();


            // 查找请求对应的权限清单
            // 根据url查找权限清淡
            for (String key : securityMetaSource.keySet()) {
                AntPathRequestMatcher requestMatcher = new AntPathRequestMatcher(key);
                if (requestMatcher.matches(request)) {
                    Collection<? extends GrantedAuthority> grantedAuthorities = authentication.get().getAuthorities();
                    Set<String> matchAuthorities = securityMetaSource.get(key);
                    boolean isGranted = false;
                    if (contains(grantedAuthorities, matchAuthorities)) {
                        isGranted = true;
                    }
                    return new AuthorizationDecision(isGranted);
                }
            }
        }

        return authenticatedAuthorizationManager.check(authentication, requestAuthorizationContext);
    }

    public boolean contains(Collection<? extends GrantedAuthority> grantedAuthorities, Collection<String> matchAuthorities) {
        if (grantedAuthorities == null || matchAuthorities == null) {
            return false;
        }
        for (GrantedAuthority grantedAuthority : grantedAuthorities) {
            for (String matchAuthority : matchAuthorities) {
                if (grantedAuthority.getAuthority().equals(matchAuthority)) {
                    return true;
                }
            }
        }
        return false;
    }

}
